///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __Pass_H__
#define __Pass_H__

#include "OgrePrerequisites.h"
#include "OgreGpuProgram.h"
#include "util/colourValue.h"
#include "OgreBlendMode.h"
#include "OgreCommon.h"
#include "OgreLight.h"
#include "OgreTextureUnitState.h"
#include "OgreUserObjectBindings.h"

namespace Ogre {

	
	
	/// Categorisation of passes for the purpose of additive lighting
	enum IlluminationStage
	{
		/// Part of the rendering which occurs without any kind of direct lighting
		IS_AMBIENT,
		/// Part of the rendering which occurs per light
		IS_PER_LIGHT,
		/// Post-lighting rendering
		IS_DECAL, 
		/// Not determined
		IS_UNKNOWN
	};

    
	class _OgreExport Pass : public MemAlloc_Resource
    {
	public:
		
		struct HashFunc
		{
			virtual uint32 operator()(const Pass* p) const = 0;
			/// Need virtual destructor in case subclasses use it
			virtual ~HashFunc() {}
		};
    protected:
        Technique* mParent;
        unsigned short mIndex; // pass index
        String mName; // optional name for the pass
        uint32 mHash; // pass hash
		bool mHashDirtyQueued; // needs to be dirtied when next loaded
        //-------------------------------------------------------------------------
        // Colour properties, only applicable in fixed-function passes
        ColourValue mAmbient;
        ColourValue mDiffuse;
        ColourValue mSpecular;
        ColourValue mEmissive;
        Real mShininess;
        TrackVertexColourType mTracking;
        //-------------------------------------------------------------------------

        //-------------------------------------------------------------------------
        // Blending factors
        SceneBlendFactor mSourceBlendFactor;
        SceneBlendFactor mDestBlendFactor;
		SceneBlendFactor mSourceBlendFactorAlpha;
		SceneBlendFactor mDestBlendFactorAlpha;

		// Used to determine if separate alpha blending should be used for color and alpha channels
		bool mSeparateBlend;

		//-------------------------------------------------------------------------
		// Blending operations
		SceneBlendOperation mBlendOperation;
		SceneBlendOperation mAlphaBlendOperation;

		// Determines if we should use separate blending operations for color and alpha channels
		bool mSeparateBlendOperation;

        //-------------------------------------------------------------------------

        //-------------------------------------------------------------------------
        // Depth buffer settings
        bool mDepthCheck;
        bool mDepthWrite;
        CompareFunction mDepthFunc;
        float mDepthBiasConstant;
		float mDepthBiasSlopeScale;
		float mDepthBiasPerIteration;

        // Colour buffer settings
        bool mColourWrite;

		// Alpha reject settings
		CompareFunction mAlphaRejectFunc;
		unsigned char mAlphaRejectVal;
		bool mAlphaToCoverageEnabled;

		// Transparent depth sorting
		bool mTransparentSorting;
		// Transparent depth sorting forced
		bool mTransparentSortingForced;
        //-------------------------------------------------------------------------

        //-------------------------------------------------------------------------
        // Culling mode
        CullingMode mCullMode;
        ManualCullingMode mManualCullMode;
        //-------------------------------------------------------------------------

        /// Lighting enabled?
        bool mLightingEnabled;
        /// Max simultaneous lights
        unsigned short mMaxSimultaneousLights;
		/// Starting light index
		unsigned short mStartLight;
		/// Run this pass once per light?
		bool mIteratePerLight;
		/// Iterate per how many lights?
		unsigned short mLightsPerIteration;
        // Should it only be run for a certain light type?
        bool mRunOnlyForOneLightType;
        Light::LightTypes mOnlyLightType;
		// With a specific light mask?
		uint32 mLightMask;

        /// Shading options
        ShadeOptions mShadeOptions;
		/// Polygon mode
		PolygonMode mPolygonMode;
		/// Normalisation
		bool mNormaliseNormals;
		bool mPolygonModeOverrideable;
        //-------------------------------------------------------------------------
        // Fog
        bool mFogOverride;
        FogMode mFogMode;
        ColourValue mFogColour;
        Real mFogStart;
        Real mFogEnd;
        Real mFogDensity;
        //-------------------------------------------------------------------------

        /// Storage of texture unit states
        typedef vector<TextureUnitState*>::type TextureUnitStates;
        TextureUnitStates mTextureUnitStates;

		// Vertex program details
		GpuProgramUsage *mVertexProgramUsage;
        // Vertex program details
        GpuProgramUsage *mShadowCasterVertexProgramUsage;
        // Fragment program details
        GpuProgramUsage *mShadowCasterFragmentProgramUsage;
        // Vertex program details
        GpuProgramUsage *mShadowReceiverVertexProgramUsage;
		// Fragment program details
		GpuProgramUsage *mFragmentProgramUsage;
		// Fragment program details
		GpuProgramUsage *mShadowReceiverFragmentProgramUsage;
		// Geometry program details
		GpuProgramUsage *mGeometryProgramUsage;
        // Is this pass queued for deletion?
        bool mQueuedForDeletion;
        // number of pass iterations to perform
        size_t mPassIterationCount;
		// point size, applies when not using per-vertex point size
		Real mPointSize;
		Real mPointMinSize;
		Real mPointMaxSize;
		bool mPointSpritesEnabled;
		bool mPointAttenuationEnabled;
		// constant, linear, quadratic coeffs
		Real mPointAttenuationCoeffs[3];
		// TU Content type lookups
		typedef vector<unsigned short>::type ContentTypeLookup;
		mutable ContentTypeLookup mShadowContentTypeLookup;
		mutable bool mContentTypeLookupBuilt;
		/// Scissoring for the light?
		bool mLightScissoring;
		/// User clip planes for light?
		bool mLightClipPlanes;
		/// Illumination stage?
		IlluminationStage mIlluminationStage;
		// User objects binding.
		UserObjectBindings	mUserObjectBindings;
		

		// Used to get scene blending flags from a blending type
		void _getBlendFlags(SceneBlendType type, SceneBlendFactor& source, SceneBlendFactor& dest);

	public:
		typedef set<Pass*>::type PassSet;
    protected:
		/// List of Passes whose hashes need recalculating
		static PassSet msDirtyHashList;
        /// The place where passes go to die
        static PassSet msPassGraveyard;
		/// The Pass hash functor
		static HashFunc* msHashFunc;
    public:
		OGRE_STATIC_MUTEX(msDirtyHashListMutex)
		OGRE_STATIC_MUTEX(msPassGraveyardMutex)
		OGRE_MUTEX(mTexUnitChangeMutex)
		OGRE_MUTEX(mGpuProgramChangeMutex)
        /// Default constructor
		Pass(Technique* parent, unsigned short index);
        /// Copy constructor
        Pass(Technique* parent, unsigned short index, const Pass& oth );
        /// Operator = overload
        Pass& operator=(const Pass& oth);
        virtual ~Pass();

        /// Returns true if this pass is programmable i.e. includes either a vertex or fragment program.
        bool isProgrammable(void) const { return mVertexProgramUsage || mFragmentProgramUsage || mGeometryProgramUsage; }
        /// Returns true if this pass uses a programmable vertex pipeline
        bool hasVertexProgram(void) const { return mVertexProgramUsage != NULL; }
        /// Returns true if this pass uses a programmable fragment pipeline
        bool hasFragmentProgram(void) const { return mFragmentProgramUsage != NULL; }
        /// Returns true if this pass uses a programmable geometry pipeline
        bool hasGeometryProgram(void) const { return mGeometryProgramUsage != NULL; }
        /// Returns true if this pass uses a shadow caster vertex program
        bool hasShadowCasterVertexProgram(void) const { return mShadowCasterVertexProgramUsage != NULL; }
        /// Returns true if this pass uses a shadow caster fragment program
        bool hasShadowCasterFragmentProgram(void) const { return mShadowCasterFragmentProgramUsage != NULL; }
        /// Returns true if this pass uses a shadow receiver vertex program
        bool hasShadowReceiverVertexProgram(void) const { return mShadowReceiverVertexProgramUsage != NULL; }
        /// Returns true if this pass uses a shadow receiver fragment program
        bool hasShadowReceiverFragmentProgram(void) const { return mShadowReceiverFragmentProgramUsage != NULL; }


        /// Gets the index of this Pass in the parent Technique
        unsigned short getIndex(void) const { return mIndex; }
        /* Set the name of the pass
        @remarks
        The name of the pass is optional.  Its useful in material scripts where a material could inherit
        from another material and only want to modify a particular pass.
        */
        void setName(const String& name);
        /// get the name of the pass
        const String& getName(void) const { return mName; }

        
        void setAmbient(Real red, Real green, Real blue);

        

        void setAmbient(const ColourValue& ambient);

        
        void setDiffuse(Real red, Real green, Real blue, Real alpha);

        
        void setDiffuse(const ColourValue& diffuse);

        
        void setSpecular(Real red, Real green, Real blue, Real alpha);

        
        void setSpecular(const ColourValue& specular);

        
        void setShininess(Real val);

        
        void setSelfIllumination(Real red, Real green, Real blue);

        
        void setSelfIllumination(const ColourValue& selfIllum);

        
        void setVertexColourTracking(TrackVertexColourType tracking);

        
        Real getPointSize(void) const;

		
		void setPointSize(Real ps);

		
		void setPointSpritesEnabled(bool enabled);

		
		bool getPointSpritesEnabled(void) const;

		
		void setPointAttenuation(bool enabled,
			Real constant = 0.0f, Real linear = 1.0f, Real quadratic = 0.0f);

		
		bool isPointAttenuationEnabled(void) const;

		
		Real getPointAttenuationConstant(void) const;
		
		Real getPointAttenuationLinear(void) const;
		
		Real getPointAttenuationQuadratic(void) const;

		
		void setPointMinSize(Real min);
		
		Real getPointMinSize(void) const;
		
		void setPointMaxSize(Real max);
		
		Real getPointMaxSize(void) const;

		
        const ColourValue& getAmbient(void) const;

        
        const ColourValue& getDiffuse(void) const;

        
        const ColourValue& getSpecular(void) const;

        
        const ColourValue& getSelfIllumination(void) const;

        
        Real getShininess(void) const;

        
        TrackVertexColourType getVertexColourTracking(void) const;

        
        TextureUnitState* createTextureUnitState(void);
        
        TextureUnitState* createTextureUnitState( const String& textureName, unsigned short texCoordSet = 0);
		
		void addTextureUnitState(TextureUnitState* state);
        
        TextureUnitState* getTextureUnitState(unsigned short index);
        
        TextureUnitState* getTextureUnitState(const String& name);
		
		const TextureUnitState* getTextureUnitState(unsigned short index) const;
		
		const TextureUnitState* getTextureUnitState(const String& name) const;

        
        unsigned short getTextureUnitStateIndex(const TextureUnitState* state) const;

        typedef VectorIterator<TextureUnitStates> TextureUnitStateIterator;
        
        TextureUnitStateIterator getTextureUnitStateIterator(void);

		typedef ConstVectorIterator<TextureUnitStates> ConstTextureUnitStateIterator;
		
		ConstTextureUnitStateIterator getTextureUnitStateIterator(void) const;

		
        void removeTextureUnitState(unsigned short index);

        
        void removeAllTextureUnitStates(void);

        
        unsigned short getNumTextureUnitStates(void) const
        {
            return static_cast<unsigned short>(mTextureUnitStates.size());
        }

        
        void setSceneBlending( const SceneBlendType sbt );

       
        void setSeparateSceneBlending( const SceneBlendType sbt, const SceneBlendType sbta );

        
        void setSceneBlending( const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor);

        
		void setSeparateSceneBlending( const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor, const SceneBlendFactor sourceFactorAlpha, const SceneBlendFactor destFactorAlpha );

		
		bool hasSeparateSceneBlending() const;

        
        SceneBlendFactor getSourceBlendFactor() const;

        
        SceneBlendFactor getDestBlendFactor() const;

	    
		SceneBlendFactor getSourceBlendFactorAlpha() const;

	    
		SceneBlendFactor getDestBlendFactorAlpha() const;

		
		void setSceneBlendingOperation(SceneBlendOperation op);

		
		void setSeparateSceneBlendingOperation(SceneBlendOperation op, SceneBlendOperation alphaOp);

		
		bool hasSeparateSceneBlendingOperations() const;

		
		SceneBlendOperation getSceneBlendingOperation() const;

		
		SceneBlendOperation getSceneBlendingOperationAlpha() const;

		
		bool isTransparent(void) const;

		
        void setDepthCheckEnabled(bool enabled);

        
        bool getDepthCheckEnabled(void) const;

        
        void setDepthWriteEnabled(bool enabled);

        
        bool getDepthWriteEnabled(void) const;

        
        void setDepthFunction( CompareFunction func );
        
        CompareFunction getDepthFunction(void) const;

		
		void setColourWriteEnabled(bool enabled);
		
		bool getColourWriteEnabled(void) const;

        
        void setCullingMode( CullingMode mode );

        
        CullingMode getCullingMode(void) const;

        
        void setManualCullingMode( ManualCullingMode mode );

        
        ManualCullingMode getManualCullingMode(void) const;

        
        void setLightingEnabled(bool enabled);

        
        bool getLightingEnabled(void) const;

        
        void setMaxSimultaneousLights(unsigned short maxLights);
        
        unsigned short getMaxSimultaneousLights(void) const;

		
		void setStartLight(unsigned short startLight);
		
		unsigned short getStartLight(void) const;

		
		void setLightMask(uint32 mask);
		
		uint32 getLightMask() const;

        
        void setShadingMode( ShadeOptions mode );

        
        ShadeOptions getShadingMode(void) const;

		
		void setPolygonMode( PolygonMode mode );

		
		PolygonMode getPolygonMode(void) const;

		
		virtual void setPolygonModeOverrideable(bool override)
		{
			mPolygonModeOverrideable = override;
		}

		
		virtual bool getPolygonModeOverrideable(void) const
		{
			return mPolygonModeOverrideable;
		}
        
        void setFog(
            bool overrideScene,
            FogMode mode = FOG_NONE,
            const ColourValue& colour = ColourValue::White,
            Real expDensity = 0.001, Real linearStart = 0.0, Real linearEnd = 1.0 );

        
        bool getFogOverride(void) const;

        
        FogMode getFogMode(void) const;

        
        const ColourValue& getFogColour(void) const;

        
        Real getFogStart(void) const;

        
        Real getFogEnd(void) const;

        
        Real getFogDensity(void) const;

        
        void setDepthBias(float constantBias, float slopeScaleBias = 0.0f);

        
        float getDepthBiasConstant(void) const;
		
		float getDepthBiasSlopeScale(void) const;
		
		void setIterationDepthBias(float biasPerIteration);
		
		float getIterationDepthBias() const;

        
        void setAlphaRejectSettings(CompareFunction func, unsigned char value, bool alphaToCoverageEnabled = false);

		
		void setAlphaRejectFunction(CompareFunction func);

		
		void setAlphaRejectValue(unsigned char val);

		
		CompareFunction getAlphaRejectFunction(void) const { return mAlphaRejectFunc; }

        
		unsigned char getAlphaRejectValue(void) const { return mAlphaRejectVal; }

		
		void setAlphaToCoverageEnabled(bool enabled);

		
		bool isAlphaToCoverageEnabled() const { return mAlphaToCoverageEnabled; }

        
        void setTransparentSortingEnabled(bool enabled);

        
		bool getTransparentSortingEnabled(void) const;

        
        void setTransparentSortingForced(bool enabled);

        
		bool getTransparentSortingForced(void) const;

		
        void setIteratePerLight(bool enabled,
            bool onlyForOneLightType = true, Light::LightTypes lightType = Light::LT_POINT);

        
		bool getIteratePerLight(void) const { return mIteratePerLight; }
        
        bool getRunOnlyForOneLightType(void) const { return mRunOnlyForOneLightType; }
        
        Light::LightTypes getOnlyLightType() const { return mOnlyLightType; }

		
		void setLightCountPerIteration(unsigned short c);
		
		unsigned short getLightCountPerIteration(void) const;
		
		/// Gets the parent Technique
        Technique* getParent(void) const { return mParent; }

		/// Gets the resource group of the ultimate parent Material
		const String& getResourceGroup(void) const;

		
		void setVertexProgram(const String& name, bool resetParams = true);
		
		void setVertexProgramParameters(GpuProgramParametersSharedPtr params);
		
		const String& getVertexProgramName(void) const;
        
        GpuProgramParametersSharedPtr getVertexProgramParameters(void) const;
		
		const GpuProgramPtr& getVertexProgram(void) const;


        
        void setShadowCasterVertexProgram(const String& name);
        
        void setShadowCasterVertexProgramParameters(GpuProgramParametersSharedPtr params);
        
        const String& getShadowCasterVertexProgramName(void) const;
        
        GpuProgramParametersSharedPtr getShadowCasterVertexProgramParameters(void) const;
        
        const GpuProgramPtr& getShadowCasterVertexProgram(void) const;

        
        void setShadowCasterFragmentProgram(const String& name);
        
        void setShadowCasterFragmentProgramParameters(GpuProgramParametersSharedPtr params);
        
        const String& getShadowCasterFragmentProgramName(void) const;
        
        GpuProgramParametersSharedPtr getShadowCasterFragmentProgramParameters(void) const;
        
        const GpuProgramPtr& getShadowCasterFragmentProgram(void) const;

        
        void setShadowReceiverVertexProgram(const String& name);
        
        void setShadowReceiverVertexProgramParameters(GpuProgramParametersSharedPtr params);

		
		void setShadowReceiverFragmentProgram(const String& name);
        
        void setShadowReceiverFragmentProgramParameters(GpuProgramParametersSharedPtr params);

        
        const String& getShadowReceiverVertexProgramName(void) const;
        
        GpuProgramParametersSharedPtr getShadowReceiverVertexProgramParameters(void) const;
        
        const GpuProgramPtr& getShadowReceiverVertexProgram(void) const;

		
		const String& getShadowReceiverFragmentProgramName(void) const;
		
		GpuProgramParametersSharedPtr getShadowReceiverFragmentProgramParameters(void) const;
		
		const GpuProgramPtr& getShadowReceiverFragmentProgram(void) const;

		
		void setFragmentProgram(const String& name, bool resetParams = true);
		
		void setFragmentProgramParameters(GpuProgramParametersSharedPtr params);
		
		const String& getFragmentProgramName(void) const;
		
		GpuProgramParametersSharedPtr getFragmentProgramParameters(void) const;
		
		const GpuProgramPtr& getFragmentProgram(void) const;

		
		void setGeometryProgram(const String& name, bool resetParams = true);
		
		void setGeometryProgramParameters(GpuProgramParametersSharedPtr params);
		
		const String& getGeometryProgramName(void) const;
		
		GpuProgramParametersSharedPtr getGeometryProgramParameters(void) const;
		
		const GpuProgramPtr& getGeometryProgram(void) const;

		
		Pass* _split(unsigned short numUnits);

		
		void _notifyIndex(unsigned short index);

		
		void _prepare(void);
		
		void _unprepare(void);
		
		void _load(void);
		
		void _unload(void);
        // Is this loaded?
        bool isLoaded(void) const;

        
        uint32 getHash(void) const { return mHash; }
		/// Mark the hash as dirty
		void _dirtyHash(void);
        
        void _recalculateHash(void);
        
        void _notifyNeedsRecompile(void);

		
		void _updateAutoParams(const AutoParamDataSource* source, uint16 variabilityMask) const;

		
		unsigned short _getTextureUnitWithContentTypeIndex(
			TextureUnitState::ContentType contentType, unsigned short index) const;

        
        void setTextureFiltering(TextureFilterOptions filterType);
        
        void setTextureAnisotropy(unsigned int maxAniso);
		
		void setNormaliseNormals(bool normalise) { mNormaliseNormals = normalise; }

		
		bool getNormaliseNormals(void) const {return mNormaliseNormals; }

		
		static const PassSet& getDirtyHashList(void)
		{ return msDirtyHashList; }
        
        static const PassSet& getPassGraveyard(void)
        { return msPassGraveyard; }
		
		static void clearDirtyHashList(void);

        
        static void processPendingPassUpdates(void);

        
        void queueForDeletion(void);

        
        bool isAmbientOnly(void) const;

        
        void setPassIterationCount(const size_t count) { mPassIterationCount = count; }

        
        size_t getPassIterationCount(void) const { return mPassIterationCount; }

        
        bool applyTextureAliases(const AliasTextureNamePairList& aliasList, const bool apply = true) const;

		
		void setLightScissoringEnabled(bool enabled) { mLightScissoring = enabled; }
		
		bool getLightScissoringEnabled() const { return mLightScissoring; }

		
		void setLightClipPlanesEnabled(bool enabled) { mLightClipPlanes = enabled; }
		
		bool getLightClipPlanesEnabled() const { return mLightClipPlanes; }

		
		void setIlluminationStage(IlluminationStage is) { mIlluminationStage = is; }
		/// Get the manually assigned illumination stage, if any
		IlluminationStage getIlluminationStage() const { return mIlluminationStage; }
		
		enum BuiltinHashFunction
		{
			
			MIN_TEXTURE_CHANGE,
			
			MIN_GPU_PROGRAM_CHANGE
		};
		
		static void setHashFunction(BuiltinHashFunction builtin);

		
		static void setHashFunction(HashFunc* hashFunc) { msHashFunc = hashFunc; }

		
		static HashFunc* getHashFunction(void) { return msHashFunc; }

		
		static HashFunc* getBuiltinHashFunction(BuiltinHashFunction builtin);

		
		UserObjectBindings&	getUserObjectBindings() { return mUserObjectBindings; }

		
		const UserObjectBindings& getUserObjectBindings() const { return mUserObjectBindings; }
    };

    
	struct IlluminationPass : public MemAlloc_Resource
    {
        IlluminationStage stage;
        /// The pass to use in this stage
        Pass* pass;
        /// Whether this pass is one which should be deleted itself
        bool destroyOnShutdown;
        /// The original pass which spawned this one
        Pass* originalPass;

		IlluminationPass() {}
    };

    typedef vector<IlluminationPass*>::type IlluminationPassList;

	
	

}

#endif
